package com.fmatos.amazingwallpapers.imagemanagement;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.inject.Inject;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Environment;
import android.util.Log;

public class FileManager {

	private static final String TAG = FileManager.class.getSimpleName();

	
	private static final int MAX_PIXELS = 1500 * 1500;
	private static final int MAX_DIMENSION = 4096;  // "Bitmap too large to be uploaded into a texture

	private static final int MAX_THUMB_PIXELS = 100 * 1000;
	private static final int MAX_THUMB_DIMENSION = 400;

    private Context context;

//		TODO to get those images in the gallery view: call	 MediaScannerConnection.scanFile(context, paths, mimeTypes, callback);


	@Inject    
    public FileManager(Context context) {
        this.context = context;
    }

	public String writeFileToRandomPath(InputStream istream,String albumName) {
		String filename = getRandomAvailableFilename(albumName);

        if( filename == null ) {
            throw new FolderNotAvailableException("Couldn't find a folder to write files to");
        }
		writeBytesToFile(filename,istream);
		
		return filename;
	}

    public boolean deleteFile(String filename) {

        File file = new File(filename);
        return file.delete();
//        myFile.delete(); for external file
//        context.deleteFile(filename); // for internal file
    }

	public Bitmap loadThumbnailFromPath(String filePath) throws FileNotAvailableException {
		return loadBitmapFromPath(filePath,true);
	}
	
	public Bitmap loadImageFromPath(String filePath) throws FileNotAvailableException {
		return loadBitmapFromPath(filePath,false);
	}
	
	private Bitmap loadBitmapFromPath(String filePath,boolean isThumbnail) throws FileNotAvailableException {
		// 4000 x 3000 images are not ok (doesn't have enough memory on S4)
		// but 2880 x 1800 are
		
		if ( ! isFileExist(filePath)) {
			throw new FileNotAvailableException(filePath);
		}
		
		Bitmap bm =null;
		
		Options opts = new Options();
		opts.inJustDecodeBounds= true;
		BitmapFactory.decodeFile(filePath, opts );
		
		Options optimalOpts = computeOptimalOpts(opts,isThumbnail);
		
		// TODO still get out of memory error sometimes here
		try {
			bm = BitmapFactory.decodeFile(filePath, optimalOpts ); //when image is corrupted it returns  skia  ---- decoder->decode returned false / outHeight = -1 outWidth = -1  (note that the decodebounds worked fine)
		} catch (OutOfMemoryError e) {
			bm = null;
//			Toast.makeText(context, "asdasdas", Toast.LENGTH_LONG);
			Log.e(TAG, "OOM error " + filePath);
		}
		
		if ( bm == null) {
			Log.i(TAG, "Couldn't get bitmap for file " + filePath);
		}

        return bm;
	}

	
	public boolean isImageGif(String filePath) {
		Options opts = new Options();
		opts.inJustDecodeBounds= true;
		BitmapFactory.decodeFile(filePath, opts );

		Log.i(TAG,"Mime type " + opts.outMimeType );
		
		String GIF = "image/gif";
		
		return GIF.equals(opts.outMimeType);

	}

	public boolean isImageHealthy(String filePath) {
		
		Bitmap bm = null;
		try {
			bm = loadThumbnailFromPath(filePath);
		} catch (FileNotAvailableException e) {
			Log.w(TAG,"Downloaded image " + filePath + " is not sane");
			e.printStackTrace();
		}
		return bm != null;
	}

	private Options computeOptimalOpts(Options opts, boolean isThumbnail) {
		
		Options newOpts = new Options();
		newOpts.inSampleSize = 1;
		
		
		int height = opts.outHeight;
		int width = opts.outWidth;
		
		int maxPixels;
		int maxDimention;
		
		if ( isThumbnail ) {
			maxPixels = MAX_THUMB_PIXELS;
			maxDimention = MAX_THUMB_DIMENSION;
			
		} else {
			maxPixels = MAX_PIXELS;
			maxDimention = MAX_DIMENSION;
		}
		
		while (height * width > maxPixels  || height > maxDimention || width > maxDimention ) {
		
			newOpts.inSampleSize *= 2;
			
			height = opts.outHeight / newOpts.inSampleSize;
			width = opts.outWidth / newOpts.inSampleSize;
		
		//	Log.i(TAG,"Image subsampled to (" + width  + "x" + height  + ") --> scale = " + newOpts.inSampleSize);
		}
		
		return newOpts;
		
	}


	/**
	 * Returns the full path of the directory where images are stored
	 * @return
	 */
	public String getGalleryFolderPath() {

        File baseFolder = getExternalStorageFolder();

        if ( baseFolder == null ) {
            baseFolder = getInternalStorageFolder();
        }

        if ( baseFolder == null ) {
            return null;
        }

        File folder = new File(baseFolder, "Amazing Wallpapers");

        if ( ! folder.exists() && !folder.mkdirs()) {
            Log.e(TAG, "Directory not created");
            return null;
        }

        return folder.getPath();

    }

    private File getInternalStorageFolder() {

//        File baseFolder = Environment.getDataDirectory(); --> cant create folders here
        File baseFolder = context.getFilesDir();

        Log.d(TAG,"Basefolder is " + baseFolder.toString());

        return baseFolder;
    }

    private File getExternalStorageFolder() {

		if ( ! Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ) {
			return null;
		}
		
		File baseFolder = Environment.getExternalStoragePublicDirectory(
	            Environment.DIRECTORY_PICTURES);

        return baseFolder;
	}
	
	/**
	 * Creates a random file name that does not exist yet
	 * @return
	 */
	private String getRandomAvailableFilename(String albumName) {
		// TODO receive file extension as parameter

		 File folder = new File(getGalleryFolderPath());
		 File file = null;
		 try {
			file = File.createTempFile(albumName + "-", ".jpg",folder);
		} catch (IOException e) {
			Log.w(TAG,"Error creating random filename: " + e.getMessage());
			e.printStackTrace();
		}
		 
		if ( file != null ) {
			return file.getAbsolutePath();
		} else {
			return null;
		}

	}
		
	private int writeBytesToFile(String filename, InputStream istream) {

		int totalBytes = 0;
		FileOutputStream fos = null;

		if ( istream == null ) {
			return 0;
		}
		
		try {
			fos = new FileOutputStream(new File(filename));

			byte[] buf = new byte[8192];
			
		    while (true) {
		      int length = istream.read(buf);
		      if (length < 0)
		        break;
		      totalBytes += length;
		      fos.write(buf, 0, length);
		    }
		    
//		    Log.d(TAG,"Wrote " + totalBytes + " to file " + filename);
			fos.flush();
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}

		finally {
			try {
				if (fos != null) {
					fos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		return totalBytes;
	}


	/**
	 * Checks that file contains valid bitmap (at least 100 bytes)
	 * @param filename
	 * @return
	 */
	public boolean isFileExist(String filename) {
		if ( filename == null ) {
			return false;
		}
		
		File file = new File(filename);
		if ( file.isFile() && file.canRead() && (file.length() > 100) ) {
			return true;
		} else { 
			return false;
		}
	}




}
